package com.vecspace.database.model;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;

import org.apache.commons.lang3.StringUtils;

import com.vecspace.common.cache.InMemoryCache;
import com.vecspace.exception.HException;

public class PojoManager {
	private static final String cacheName = "db.model.PojoFieldManager";
	private static final String cacheName2 = "db.model.PojoFilterFieldManager";
	private static final String cacheNameIdColumn = "db.model.PojoIdColumn";
	private static final String cacheNameTableName = "db.model.PojoIdColumn";

	/**根据POJO clazz的@Table注解获取表名
	 *
	 * @param clazz
	 * @author wanghua
	 * @date 2021/11/10  9:32
	 * @return java.lang.String
	 **/
	public static String getTableName(Class<?> clazz){
		String key = clazz.getName();
		String tableName = (String)InMemoryCache.DEFAULT().get(cacheNameTableName, key);
		if(tableName == null) {
			Table tableAnno = clazz.getAnnotation(Table.class);
			if (tableAnno == null) return "";
			String schema = tableAnno.schema();
			String realDbSchema = null;
			if (StringUtils.isNotBlank(schema)) {
				realDbSchema = DbSchemas.getRealDbSchema(schema);
			}
			if (StringUtils.isBlank(realDbSchema)) {
				tableName = tableAnno.name();
			} else {
				tableName = realDbSchema + "." + tableAnno.name();
			}
			InMemoryCache.DEFAULT().put(cacheNameTableName, key, tableName);
		}
		tableName = (String)InMemoryCache.DEFAULT().get(cacheNameTableName, key);
		return tableName;
	}

	/**根据POJO clazz中的@Id和@Column注解获取id字段名
	 *
	 * @param clazz
	 * @author wanghua
	 * @date 2021/11/10  9:40
	 * @return java.lang.String
	 **/
	public static String getIdColumnName(Class<?> clazz) throws Exception {
		String key = clazz.getName()+".id";
		String columnName = (String)InMemoryCache.DEFAULT().get(cacheNameIdColumn, key);
		if(columnName == null){
			BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
			PropertyDescriptor[] propertyDescriptors =  beanInfo.getPropertyDescriptors();
			if(propertyDescriptors != null && propertyDescriptors.length > 0) {
				for(PropertyDescriptor propDesc : propertyDescriptors) {
					Method readMethod = propDesc.getReadMethod();
					if(readMethod == null)continue;
					Id idAnno = readMethod.getAnnotation(Id.class);
					if(idAnno != null) {
						Column colAnno = readMethod.getAnnotation(Column.class);
						String idColumnName = colAnno.name();
						InMemoryCache.DEFAULT().put(cacheNameIdColumn, key, idColumnName);
					}
				}
			}
		}
		columnName = (String)InMemoryCache.DEFAULT().get(cacheNameIdColumn, key);
		return columnName;
	}

	/**根据POJO的setter属性上的Column注解，获取字段名。如果没有获取到对应的字段名，则返回默认值
	 * @param clazz
	 * @param propName
	 * @param defaultColumnName 默认返回值
	 * @return
	 * @throws IntrospectionException 
	 * @author: wanghua
	 */
	public static String getColumnName(Class<?> clazz, String propName, String defaultColumnName) throws IntrospectionException {
		String colName = getColumnName(clazz, propName);
		if(colName == null || colName.length() == 0) {
			colName = defaultColumnName;
		}
		return colName;
	}
	/**根据POJO的setter属性上的Column注解，获取字段名(在数据库中的名称,比如 USER_NAME)。如果没有获取到对应的字段名，则返回空值。
	 * @param clazz POJO
	 * @param propName POJO的属性名
	 * @return 字段名
	 * @throws IntrospectionException  
	 * @author: wanghua
	 */
	public static String getColumnName(Class<?> clazz, String propName) throws IntrospectionException {
		if(propName == null || propName.trim().length() == 0)return null;
		String columnName = "";
		String className = clazz.getName();
		String key = className + "." + propName;
		columnName = (String)InMemoryCache.DEFAULT().get(cacheName, key);
		if(columnName == null) {
			BeanInfo beanInfo = Introspector.getBeanInfo(clazz); 
	        PropertyDescriptor[] propertyDescriptors =  beanInfo.getPropertyDescriptors();
	        if(propertyDescriptors != null && propertyDescriptors.length > 0) {
	        	for(PropertyDescriptor propDesc : propertyDescriptors) {
	        		Method readMethod = propDesc.getReadMethod();
	        		if(readMethod == null)continue;
	        		Column columnAnno = readMethod.getAnnotation(javax.persistence.Column.class);
	        		if(columnAnno != null) {
	        			String propKey = className + "." + propDesc.getName();
	        			columnName = columnAnno.name();
	        			InMemoryCache.DEFAULT().put(cacheName, propKey, columnName);
	        		}
	        	}
	        }
	        columnName = (String)InMemoryCache.DEFAULT().get(cacheName, key);
		}
		return columnName;
	}
	/**根据POJO的setter属性上的Column注解，获取在where条件中使用的字段名（优先从获取columnDefinition(可能的形式为t2.USER_NAME)，其次才是 name，）。如果没有获取到对应的字段名，则返回空值。
	 * @param clazz POJO
	 * @param propName POJO的属性名
	 * @param withTableName 返回的字段名是否含表名， 比如 t1.NAME
	 * @return 字段名
	 * @throws IntrospectionException  
	 * @author: wanghua
	 */
	public static String getColumnFilterName(Class<?> clazz, String propName, boolean withTableName) throws IntrospectionException {
		if(propName == null || propName.trim().length() == 0)return null;
		String columnName = "";
		String className = clazz.getName();
		String key = className + "." + propName;
		columnName = (String)InMemoryCache.DEFAULT().get(cacheName2, key);
		if(columnName == null) {
			BeanInfo beanInfo = Introspector.getBeanInfo(clazz); 
	        PropertyDescriptor[] propertyDescriptors =  beanInfo.getPropertyDescriptors();
	        if(propertyDescriptors != null && propertyDescriptors.length > 0) {
	        	for(PropertyDescriptor propDesc : propertyDescriptors) {
	        		Method readMethod = propDesc.getReadMethod();
	        		if(readMethod == null)continue;
	        		Column columnAnno = readMethod.getAnnotation(javax.persistence.Column.class);
	        		if(columnAnno != null) {
	        			String propKey = className + "." + propDesc.getName();
	        			String filterColumnName = columnAnno.columnDefinition();
	        			if(StringUtils.isBlank(filterColumnName)) {
	        				filterColumnName = columnAnno.name();
	        				if(withTableName) {
								String tableName = columnAnno.table();
								if (StringUtils.isBlank(tableName)) {
									tableName = "t1";//默认表别名为t1
								}
								filterColumnName = tableName + "." + filterColumnName;
							}
	        			}
	        			InMemoryCache.DEFAULT().put(cacheName2, propKey, filterColumnName);
	        		}
	        	}
	        }
	        columnName = (String)InMemoryCache.DEFAULT().get(cacheName2, key);
		}
		return columnName;
	}
	
	/**根据字段/属性名数组，查找指定属性名对应的字段名
	 * 
	 * @param columnNames 字段名数组（不区分大小写）
	 * @param propNames 属性名数组（区分大小写）
	 * @param propName 属性名（区分大小写）
	 * @return 如果没有匹配的ColumnName，则返回propName
	 * @throws HException
	 * @author: wanghua
	 */
	public static String findColumnName(String[] columnNames, String[] propNames, String propName) throws HException {
		if(propName == null || propName.length() == 0)return null;
		if(columnNames == null || propNames == null)return null;
		if(columnNames.length != propNames.length) throw new HException("columnNames.length != propNames.length");
		for(int i=0; i<columnNames.length; ++i) {
			if(propName.equals(propNames[i])) {
				return columnNames[i];
			}
		}
		return propName;
	}
}
